#include<export_obj.h>
#include<Mesh/libcell_iterator.h>

#define Matrix4x4 Viewer_Matrix4x4_
#define quote lib_cell_quote

static inline double *out_product(double *a,double*b)
{
    double* re=(double*)malloc(sizeof(double)*3);
    
    re[0]=a[1]*b[2]-a[2]*b[1];
    re[1]=-a[0]*b[2]+a[2]*b[0];
    re[2]=a[0]*b[1]-a[1]*b[0];
    return re; 
}

static double * get_coordinate_in_another_coordinate_system(double* p,double* a1,double *a2,double*a3)
{
    Matrix4x4* m=(Matrix4x4*)malloc(sizeof(Matrix4x4));
    Matrix4x4_init_double(m);
    double* data=(double*)(m->data);
    data[0*4+0]=a1[0]; data[1*4+0]=a1[1];  data[2*4+0]=a1[2];   
    data[0*4+1]=a2[0]; data[1*4+1]=a2[1];  data[2*4+1]=a2[2];
    data[0*4+2]=a3[0]; data[1*4+2]=a3[1];  data[2*4+2]=a3[2];
    Matrix4x4* mi=m->inverse(m);
    if(mi==NULL)
    {
        Matrix4x4_free(m);
        return NULL;
    } 
    data=(double*)(mi->data);
    double * re=(double*)malloc(sizeof(double)*3); 
    memset(re,0,sizeof(double)*3);
    for(int i=0;i<3;i++)
    {
        re[i]=0;
       for(int j=0;j<3;j++)
       {

            re[i]+=data[i*4+j]*p[j];
       } 

    }
    Matrix4x4_free(m);
    Matrix4x4_free(mi);
    return re;
}
//return the triangle coordinate of p in p1 p2 p3
static double* get_triangle_coordinate(double* p,double * p1,double*p2,double* p3 )
{

    double a1[3]={p1[0]-p3[0],p1[1]-p3[1],p1[2]-p3[2]};
    double a2[3]={p2[0]-p3[0],p2[1]-p3[1],p2[2]-p3[2]};
    double pp[3]={p[0]-p3[0],p[1]-p3[1],p[2]-p3[2]};
    double* n=out_product(a1,a2);
    double* coord=get_coordinate_in_another_coordinate_system(pp,a1,a2,n);

    SAFE_FREE(n);
    if(coord==NULL)
    {
        return NULL;
    }
    double *re=(double*)malloc(sizeof(double)*3);
    re[0]=coord[0];re[1]=coord[1];
    re[2]=1-re[0]-re[1]; 
    SAFE_FREE(coord);
    return re;
}

int is_point_in_triangle(double* p,double *a1,double *a2,double *a3)
{
    double a[3]={a2[0]-a1[0],a2[1]-a1[1],a2[2]-a1[2]};
    double b[3]={a3[0]-a1[0],a3[1]-a1[1],a3[2]-a1[2]};
    double * n= out_product(a,b);
    if(n==NULL)
    {
        return 0;
    } 
    double *coord=get_coordinate_in_another_coordinate_system(p,a,b,n);
    SAFE_FREE(n);
    if(coord==NULL)
    {
        return 0;
    }
    int re=0;
    if(coord[0]>=0&&coord[1]>=0&&coord[0]+coord[1]<=1)
    {
        re=1;
    }
    SAFE_FREE(coord);
    return re;
}




void my_chuli_texture(Mesh* m,Mesh* m1,Int_RB_Tree* tree)
{
    OBJ_MESH_PROP* omp=(OBJ_MESH_PROP*)malloc(sizeof(OBJ_MESH_PROP));
    obj_mesh_prop_init(omp);
    OBJ_MESH_PROP* omp1=(OBJ_MESH_PROP*)(m1->prop);

    omp->mtlibname=(char*)malloc(sizeof(char)*(strlen(omp1->mtlibname)+1));
    strcpy(omp->mtlibname,omp1->mtlibname);
    //printf("m1 mtl name:%s\n",omp1->mtlname);
    m->prop=omp;
    for(auto cit=m->c_begin(m);cit!=m->c_end(m);cit++)
    {

        template_c* c1=quote(cit);
        template_c* c=(template_c*)(tree->find(tree,c1->id));
        OBJ_CELL_PROP* ocp=(OBJ_CELL_PROP*)(c->prop);
        OBJ_CELL_PROP* ocp1=(OBJ_CELL_PROP*)malloc(sizeof(OBJ_CELL_PROP)*c1->vertices_size);
        c1->prop=ocp1; 

        for(int i=0;i<c1->vertices_size;i++)
        {
            obj_cell_prop_init(&ocp1[i]);
            ocp1[i].mtlname=(char*)malloc(sizeof(char)*(strlen(ocp->mtlname)+1));
            strcpy(ocp1[i].mtlname,ocp->mtlname);
            double *coord=get_triangle_coordinate(c1->vertices[i]->point,c->vertices[0]->point,c->vertices[1]->point,c->vertices[2]->point);
            //printf("coord %lf %lf %lf\n",coord[0],coord[1],coord[2]);
            if(coord==NULL)
            {
                coord=(double*)malloc(sizeof(double)*3);
                coord[0]=1.0/3.0;coord[1]=1.0/3.0;coord[2]=1.0/3.0;
                //continue;
            }
            for(int j=0;j<3;j++)
            {
                ocp1[i].vt[j]=coord[0]*ocp[0].vt[j]+coord[1]*ocp[1].vt[j]+coord[2]*ocp[2].vt[j];
            } 
            SAFE_FREE(coord); 
        }
    } 
}


void export_obj_from_mesh(Mesh* m,char* filename)
{
    OBJ_MESH_PROP* omp=(OBJ_MESH_PROP*)(m->prop);
    Node* node=NULL;
    for(auto cit=m->c_begin(m);cit!=m->c_end(m);cit++)
    {
        node=node_overlying(node,quote(cit));
    }

    omp==NULL?export_obj_from_node(node,filename,NULL):export_obj_from_node(node,filename,omp->mtlibname);

    free_node(node);
}

